<!DOCTYPE HTML>
<!--
	Dimension by HTML5 UP
	html5up.net | @ajlkn
	Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
-->
<html>
 <head>
  <title>
   Dimension by HTML5 UP
  </title>
  <!-- <meta charset="utf-8" /> -->
  <!-- <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" /> -->
  <meta charset="utf-8"/>
  <meta content="width=device-width,initial-scale=1.0" name="viewport"/>
  <link href="../../assets/css/article.css" rel="stylesheet"/>
  <link href="https://cdn.bootcss.com/highlight.js/9.15.8/styles/github.min.css" rel="stylesheet"/>
  <noscript>
   <link href="../../assets/css/noscript.css" rel="stylesheet"/>
  </noscript>
 </head>
 <body>
  <div id="app">
  </div>
  <!-- built files will be auto injected -->
 </body>
 <body class="is-preload">
  <!-- Wrapper -->
  <div id="wrapper">
   <!-- Main -->
   <div id="main">
    <article id="article">
     <h1 id="soul-http">
      Soul 源码解析（三）HTTP请求处理概览
     </h1>
     <hr/>
     <h2 id="_1">
      简介
     </h2>
     <p>
      基于上篇：
      <a href="https://juejin.cn/post/6917865804121767944">
       Soul网关源码解析（二）代码初步运行
      </a>
      的配置，这次debug下请求处理的大致路径,验证网关模型的路径
     </p>
     <h2 id="_2">
      概览
     </h2>
     <p>
      基于示例，在切入点中打上断点，然后跟踪调用栈，查看发送一个请求是在什么地方接收的；途中经历了那些类；大致进行了那些处理
     </p>
     <p>
      最重要的，我们这次要着重查看请求是如果发送给后台服务器的
     </p>
     <p>
      还有就是如何将响应返回给客户端
     </p>
     <h2 id="debug">
      源码Debug
     </h2>
     <h4 id="_3">
      查看运行日志，寻找切入点
     </h4>
     <p>
      上篇中我们配置了 Divide 插件，让 http://localhost:9195 ,转发到了后台服务器 http://localhost:8082 上，首先不打断点运行，查看运行日志，找一个切入点：
     </p>
     <p>
      ```shell script
o.d.soul.plugin.base.AbstractSoulPlugin  : divide selector success match , selector name :neety8082
o.d.soul.plugin.base.AbstractSoulPlugin  : divide selector success match , selector name :neety8082
o.d.s.plugin.httpclient.WebClientPlugin  : The request urlPath is http://localhost:8082, retryTimes is 1
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="o">&amp;</span><span class="n">ensp</span><span class="p">;</span><span class="o">&amp;</span><span class="n">ensp</span><span class="p">;</span><span class="o">&amp;</span><span class="n">ensp</span><span class="p">;</span><span class="o">&amp;</span><span class="n">ensp</span><span class="p">;</span><span class="err">上面的日志中一个比较明显的</span> <span class="n">divide</span> <span class="err">相关的日志，是</span> <span class="n">AbstractSoulPlugin</span> <span class="err">打印出来的，</span><span class="n">win下双击shift</span><span class="err">，搜索</span> <span class="n">AbstractSoulPlugin</span> <span class="err">进入，发现是一个接口，</span><span class="n">IDEA左边向下的箭头查看它的实现</span><span class="err">，发现有一个熟系的</span> <span class="n">DividePlugin</span> <span class="err">实现类，点击进入，在一个明显的</span> <span class="n">doExecute</span> <span class="err">函数上打上断点，发起请求：</span><span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">localhost</span><span class="p">:</span><span class="mi">9195</span>

<span class="o">&amp;</span><span class="n">ensp</span><span class="p">;</span><span class="o">&amp;</span><span class="n">ensp</span><span class="p">;</span><span class="o">&amp;</span><span class="n">ensp</span><span class="p">;</span><span class="o">&amp;</span><span class="n">ensp</span><span class="p">;</span><span class="err">通过函数调用栈，发送调用的是</span> <span class="n">SoulWebHandler</span> <span class="err">，从下面的函数中可以大致看出这是一个循环遍历，遍历</span> <span class="n">plugins</span> <span class="err">进行操作</span>

<span class="o">```</span><span class="n">java</span>
    <span class="k">public</span> <span class="n">Mono</span><span class="o">&lt;</span><span class="n">Void</span><span class="o">&gt;</span> <span class="k">execute</span><span class="p">(</span><span class="k">final</span> <span class="n">ServerWebExchange</span> <span class="n">exchange</span><span class="p">)</span> <span class="err">{</span>
            <span class="k">return</span> <span class="n">Mono</span><span class="p">.</span><span class="n">defer</span><span class="p">(()</span> <span class="o">-&gt;</span> <span class="err">{</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">this</span><span class="p">.</span><span class="k">index</span> <span class="o">&lt;</span> <span class="n">plugins</span><span class="p">.</span><span class="k">size</span><span class="p">())</span> <span class="err">{</span>
                    <span class="n">SoulPlugin</span> <span class="n">plugin</span> <span class="o">=</span> <span class="n">plugins</span><span class="p">.</span><span class="k">get</span><span class="p">(</span><span class="n">this</span><span class="p">.</span><span class="k">index</span><span class="o">++</span><span class="p">);</span>
                    <span class="nb">Boolean</span> <span class="n">skip</span> <span class="o">=</span> <span class="n">plugin</span><span class="p">.</span><span class="n">skip</span><span class="p">(</span><span class="n">exchange</span><span class="p">);</span>
                    <span class="k">if</span> <span class="p">(</span><span class="n">skip</span><span class="p">)</span> <span class="err">{</span>
                        <span class="k">return</span> <span class="n">this</span><span class="p">.</span><span class="k">execute</span><span class="p">(</span><span class="n">exchange</span><span class="p">);</span>
                    <span class="err">}</span>
                    <span class="k">return</span> <span class="n">plugin</span><span class="p">.</span><span class="k">execute</span><span class="p">(</span><span class="n">exchange</span><span class="p">,</span> <span class="n">this</span><span class="p">);</span>
                <span class="err">}</span>
                <span class="k">return</span> <span class="n">Mono</span><span class="p">.</span><span class="n">empty</span><span class="p">();</span>
            <span class="err">}</span><span class="p">);</span>
        <span class="err">}</span>
</code></pre>
     </div>
     <h3 id="_4">
      跟踪调用栈
     </h3>
     <p>
      再次往前看调用栈，发送 SoulWebHandler 调用了 SoulWebHandler 的 execute
     </p>
     <div class="codehilite">
      <pre><span></span><code>    <span class="kd">public</span> <span class="n">Mono</span><span class="o">&lt;</span><span class="n">Void</span><span class="o">&gt;</span> <span class="nf">handle</span><span class="p">(</span><span class="nd">@NonNull</span> <span class="kd">final</span> <span class="n">ServerWebExchange</span> <span class="n">exchange</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">MetricsTrackerFacade</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">counterInc</span><span class="p">(</span><span class="n">MetricsLabelEnum</span><span class="p">.</span><span class="na">REQUEST_TOTAL</span><span class="p">.</span><span class="na">getName</span><span class="p">());</span>
        <span class="n">Optional</span><span class="o">&lt;</span><span class="n">HistogramMetricsTrackerDelegate</span><span class="o">&gt;</span> <span class="n">startTimer</span> <span class="o">=</span> <span class="n">MetricsTrackerFacade</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">histogramStartTimer</span><span class="p">(</span><span class="n">MetricsLabelEnum</span><span class="p">.</span><span class="na">REQUEST_LATENCY</span><span class="p">.</span><span class="na">getName</span><span class="p">());</span>
        <span class="c1">// new DefaultSoulPluginChain(plugins).execute(exchange) 明显的调用关系</span>
        <span class="k">return</span> <span class="k">new</span> <span class="n">DefaultSoulPluginChain</span><span class="p">(</span><span class="n">plugins</span><span class="p">).</span><span class="na">execute</span><span class="p">(</span><span class="n">exchange</span><span class="p">).</span><span class="na">subscribeOn</span><span class="p">(</span><span class="n">scheduler</span><span class="p">)</span>
                <span class="p">.</span><span class="na">doOnSuccess</span><span class="p">(</span><span class="n">t</span> <span class="o">-&gt;</span> <span class="n">startTimer</span><span class="p">.</span><span class="na">ifPresent</span><span class="p">(</span><span class="n">time</span> <span class="o">-&gt;</span> <span class="n">MetricsTrackerFacade</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">histogramObserveDuration</span><span class="p">(</span><span class="n">time</span><span class="p">)));</span>
    <span class="p">}</span>
</code></pre>
     </div>
     <p>
      再往前发现看不懂了，没用明显的函数传递关系，我们在上面的函数打上端口，重启程序，再次发送请求
     </p>
     <p>
      断点进来后，查看调用栈，发送调用上面函数的是 DefaultWebFilterChain
     </p>
     <div class="codehilite">
      <pre><span></span><code>    <span class="kd">public</span> <span class="n">Mono</span><span class="o">&lt;</span><span class="n">Void</span><span class="o">&gt;</span> <span class="nf">filter</span><span class="p">(</span><span class="n">ServerWebExchange</span> <span class="n">exchange</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">Mono</span><span class="p">.</span><span class="na">defer</span><span class="p">(()</span> <span class="o">-&gt;</span> <span class="p">{</span>
            <span class="c1">// 当下面都为null的时候进行调用</span>
            <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="na">currentFilter</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&amp;&amp;</span> <span class="k">this</span><span class="p">.</span><span class="na">chain</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">?</span> <span class="k">this</span><span class="p">.</span><span class="na">invokeFilter</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="na">currentFilter</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="na">chain</span><span class="p">,</span> <span class="n">exchange</span><span class="p">)</span> <span class="p">:</span> <span class="k">this</span><span class="p">.</span><span class="na">handler</span><span class="p">.</span><span class="na">handle</span><span class="p">(</span><span class="n">exchange</span><span class="p">);</span>
        <span class="p">});</span>
    <span class="p">}</span>
</code></pre>
     </div>
     <p>
      再往前查看，调用栈又看不懂了，再次在上面的函数打上断点，重启，发请求，下面就直接写类和相关函数，有特别的地方就加点说明
     </p>
     <p>
      来到 FilteringWebHandler
     </p>
     <div class="codehilite">
      <pre><span></span><code>    <span class="kd">public</span> <span class="n">Mono</span><span class="o">&lt;</span><span class="n">Void</span><span class="o">&gt;</span> <span class="nf">handle</span><span class="p">(</span><span class="n">ServerWebExchange</span> <span class="n">exchange</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="na">chain</span><span class="p">.</span><span class="na">filter</span><span class="p">(</span><span class="n">exchange</span><span class="p">);</span>
    <span class="p">}</span>
</code></pre>
     </div>
     <p>
      继续来到 WebHandlerDecorator
     </p>
     <div class="codehilite">
      <pre><span></span><code>    <span class="kd">public</span> <span class="n">Mono</span><span class="o">&lt;</span><span class="n">Void</span><span class="o">&gt;</span> <span class="nf">handle</span><span class="p">(</span><span class="n">ServerWebExchange</span> <span class="n">exchange</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="na">delegate</span><span class="p">.</span><span class="na">handle</span><span class="p">(</span><span class="n">exchange</span><span class="p">);</span>
    <span class="p">}</span>
</code></pre>
     </div>
     <p>
      来到 ExceptionHandlingWebHandler
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="n">Mono</span><span class="o">&lt;</span><span class="n">Void</span><span class="o">&gt;</span> <span class="nf">handle</span><span class="p">(</span><span class="n">ServerWebExchange</span> <span class="n">exchange</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">Mono</span> <span class="n">completion</span><span class="p">;</span>
        <span class="k">try</span> <span class="p">{</span>
            <span class="c1">// 在这进行调用</span>
            <span class="n">completion</span> <span class="o">=</span> <span class="kd">super</span><span class="p">.</span><span class="na">handle</span><span class="p">(</span><span class="n">exchange</span><span class="p">);</span>
        <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="n">Throwable</span> <span class="n">var5</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">completion</span> <span class="o">=</span> <span class="n">Mono</span><span class="p">.</span><span class="na">error</span><span class="p">(</span><span class="n">var5</span><span class="p">);</span>
        <span class="p">}</span>

        <span class="n">WebExceptionHandler</span> <span class="n">handler</span><span class="p">;</span>
        <span class="k">for</span><span class="p">(</span><span class="n">Iterator</span> <span class="n">var3</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="na">exceptionHandlers</span><span class="p">.</span><span class="na">iterator</span><span class="p">();</span> <span class="n">var3</span><span class="p">.</span><span class="na">hasNext</span><span class="p">();</span> <span class="n">completion</span> <span class="o">=</span> <span class="n">completion</span><span class="p">.</span><span class="na">onErrorResume</span><span class="p">((</span><span class="n">ex</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="p">{</span>
            <span class="k">return</span> <span class="n">handler</span><span class="p">.</span><span class="na">handle</span><span class="p">(</span><span class="n">exchange</span><span class="p">,</span> <span class="n">ex</span><span class="p">);</span>
        <span class="p">}))</span> <span class="p">{</span>
            <span class="n">handler</span> <span class="o">=</span> <span class="p">(</span><span class="n">WebExceptionHandler</span><span class="p">)</span><span class="n">var3</span><span class="p">.</span><span class="na">next</span><span class="p">();</span>
        <span class="p">}</span>

        <span class="k">return</span> <span class="n">completion</span><span class="p">;</span>
    <span class="p">}</span>
</code></pre>
     </div>
     <p>
      继续来到 HttpWebHandlerAdapter ，这个类有点关键，看到在前面一直传递的变量：exchange，exchange在这个类中生成，传递给后面的函数进行调用，而且是使用response和request生成的
     </p>
     <div class="codehilite">
      <pre><span></span><code>    <span class="kd">public</span> <span class="n">Mono</span><span class="o">&lt;</span><span class="n">Void</span><span class="o">&gt;</span> <span class="nf">handle</span><span class="p">(</span><span class="n">ServerHttpRequest</span> <span class="n">request</span><span class="p">,</span> <span class="n">ServerHttpResponse</span> <span class="n">response</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="na">forwardedHeaderTransformer</span> <span class="o">!=</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">request</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="na">forwardedHeaderTransformer</span><span class="p">.</span><span class="na">apply</span><span class="p">(</span><span class="n">request</span><span class="p">);</span>
        <span class="p">}</span>

        <span class="c1">// 重点变量 exchange 的生成</span>
        <span class="n">ServerWebExchange</span> <span class="n">exchange</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="na">createExchange</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">response</span><span class="p">);</span>
        <span class="n">LogFormatUtils</span><span class="p">.</span><span class="na">traceDebug</span><span class="p">(</span><span class="n">logger</span><span class="p">,</span> <span class="p">(</span><span class="n">traceOn</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="p">{</span>
            <span class="k">return</span> <span class="n">exchange</span><span class="p">.</span><span class="na">getLogPrefix</span><span class="p">()</span> <span class="o">+</span> <span class="k">this</span><span class="p">.</span><span class="na">formatRequest</span><span class="p">(</span><span class="n">exchange</span><span class="p">.</span><span class="na">getRequest</span><span class="p">())</span> <span class="o">+</span> <span class="p">(</span><span class="n">traceOn</span> <span class="o">?</span> <span class="s">", headers="</span> <span class="o">+</span> <span class="k">this</span><span class="p">.</span><span class="na">formatHeaders</span><span class="p">(</span><span class="n">exchange</span><span class="p">.</span><span class="na">getRequest</span><span class="p">().</span><span class="na">getHeaders</span><span class="p">())</span> <span class="p">:</span> <span class="s">""</span><span class="p">);</span>
        <span class="p">});</span>
        <span class="c1">// this.getDelegate().handle(exchange)</span>
        <span class="c1">// 通过debug可以看到 getDelete 得到的是 ExceptionHandlingWebHandler，那调用就是在这</span>
        <span class="n">Mono</span> <span class="n">var10000</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="na">getDelegate</span><span class="p">().</span><span class="na">handle</span><span class="p">(</span><span class="n">exchange</span><span class="p">).</span><span class="na">doOnSuccess</span><span class="p">((</span><span class="n">aVoid</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="p">{</span>
            <span class="k">this</span><span class="p">.</span><span class="na">logResponse</span><span class="p">(</span><span class="n">exchange</span><span class="p">);</span>
        <span class="p">}).</span><span class="na">onErrorResume</span><span class="p">((</span><span class="n">ex</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="p">{</span>
            <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="na">handleUnresolvedError</span><span class="p">(</span><span class="n">exchange</span><span class="p">,</span> <span class="n">ex</span><span class="p">);</span>
        <span class="p">});</span>
        <span class="n">response</span><span class="p">.</span><span class="na">getClass</span><span class="p">();</span>
        <span class="k">return</span> <span class="n">var10000</span><span class="p">.</span><span class="na">then</span><span class="p">(</span><span class="n">Mono</span><span class="p">.</span><span class="na">defer</span><span class="p">(</span><span class="n">response</span><span class="p">::</span><span class="n">setComplete</span><span class="p">));</span>
    <span class="p">}</span>
</code></pre>
     </div>
     <p>
      继续走到 ReactiveWebServerApplicationContext
     </p>
     <div class="codehilite">
      <pre><span></span><code>    <span class="kd">public</span> <span class="n">Mono</span><span class="o">&lt;</span><span class="n">Void</span><span class="o">&gt;</span> <span class="nf">handle</span><span class="p">(</span><span class="n">ServerHttpRequest</span> <span class="n">request</span><span class="p">,</span> <span class="n">ServerHttpResponse</span> <span class="n">response</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="na">handler</span><span class="p">.</span><span class="na">handle</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">response</span><span class="p">);</span>
        <span class="p">}</span>
</code></pre>
     </div>
     <p>
      继续走到 ReactorHttpHandlerAdapter
     </p>
     <div class="codehilite">
      <pre><span></span><code>    <span class="kd">public</span> <span class="n">Mono</span><span class="o">&lt;</span><span class="n">Void</span><span class="o">&gt;</span> <span class="nf">apply</span><span class="p">(</span><span class="n">HttpServerRequest</span> <span class="n">reactorRequest</span><span class="p">,</span> <span class="n">HttpServerResponse</span> <span class="n">reactorResponse</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">NettyDataBufferFactory</span> <span class="n">bufferFactory</span> <span class="o">=</span> <span class="k">new</span> <span class="n">NettyDataBufferFactory</span><span class="p">(</span><span class="n">reactorResponse</span><span class="p">.</span><span class="na">alloc</span><span class="p">());</span>

        <span class="k">try</span> <span class="p">{</span>
            <span class="c1">// exchange 需要的 request 和 response 的生成</span>
            <span class="n">ReactorServerHttpRequest</span> <span class="n">request</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ReactorServerHttpRequest</span><span class="p">(</span><span class="n">reactorRequest</span><span class="p">,</span> <span class="n">bufferFactory</span><span class="p">);</span>
            <span class="n">ServerHttpResponse</span> <span class="n">response</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ReactorServerHttpResponse</span><span class="p">(</span><span class="n">reactorResponse</span><span class="p">,</span> <span class="n">bufferFactory</span><span class="p">);</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">request</span><span class="p">.</span><span class="na">getMethod</span><span class="p">()</span> <span class="o">==</span> <span class="n">HttpMethod</span><span class="p">.</span><span class="na">HEAD</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">response</span> <span class="o">=</span> <span class="k">new</span> <span class="n">HttpHeadResponseDecorator</span><span class="p">((</span><span class="n">ServerHttpResponse</span><span class="p">)</span><span class="n">response</span><span class="p">);</span>
            <span class="p">}</span>

            <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="na">httpHandler</span><span class="p">.</span><span class="na">handle</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="p">(</span><span class="n">ServerHttpResponse</span><span class="p">)</span><span class="n">response</span><span class="p">).</span><span class="na">doOnError</span><span class="p">((</span><span class="n">ex</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="p">{</span>
                <span class="n">logger</span><span class="p">.</span><span class="na">trace</span><span class="p">(</span><span class="n">request</span><span class="p">.</span><span class="na">getLogPrefix</span><span class="p">()</span> <span class="o">+</span> <span class="s">"Failed to complete: "</span> <span class="o">+</span> <span class="n">ex</span><span class="p">.</span><span class="na">getMessage</span><span class="p">());</span>
            <span class="p">}).</span><span class="na">doOnSuccess</span><span class="p">((</span><span class="n">aVoid</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="p">{</span>
                <span class="n">logger</span><span class="p">.</span><span class="na">trace</span><span class="p">(</span><span class="n">request</span><span class="p">.</span><span class="na">getLogPrefix</span><span class="p">()</span> <span class="o">+</span> <span class="s">"Handling completed"</span><span class="p">);</span>
            <span class="p">});</span>
        <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="n">URISyntaxException</span> <span class="n">var6</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">logger</span><span class="p">.</span><span class="na">isDebugEnabled</span><span class="p">())</span> <span class="p">{</span>
                <span class="n">logger</span><span class="p">.</span><span class="na">debug</span><span class="p">(</span><span class="s">"Failed to get request URI: "</span> <span class="o">+</span> <span class="n">var6</span><span class="p">.</span><span class="na">getMessage</span><span class="p">());</span>
            <span class="p">}</span>

            <span class="n">reactorResponse</span><span class="p">.</span><span class="na">status</span><span class="p">(</span><span class="n">HttpResponseStatus</span><span class="p">.</span><span class="na">BAD_REQUEST</span><span class="p">);</span>
            <span class="k">return</span> <span class="n">Mono</span><span class="p">.</span><span class="na">empty</span><span class="p">();</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre>
     </div>
     <p>
      继续走到 HttpServerHandle
     </p>
     <div class="codehilite">
      <pre><span></span><code>    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onStateChange</span><span class="p">(</span><span class="n">Connection</span> <span class="n">connection</span><span class="p">,</span> <span class="n">State</span> <span class="n">newState</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">newState</span> <span class="o">==</span> <span class="n">HttpServerState</span><span class="p">.</span><span class="na">REQUEST_RECEIVED</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">try</span> <span class="p">{</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">log</span><span class="p">.</span><span class="na">isDebugEnabled</span><span class="p">())</span> <span class="p">{</span>
                    <span class="n">log</span><span class="p">.</span><span class="na">debug</span><span class="p">(</span><span class="n">ReactorNetty</span><span class="p">.</span><span class="na">format</span><span class="p">(</span><span class="n">connection</span><span class="p">.</span><span class="na">channel</span><span class="p">(),</span> <span class="s">"Handler is being applied: {}"</span><span class="p">),</span> <span class="k">new</span> <span class="n">Object</span><span class="o">[]</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="na">handler</span><span class="p">});</span>
                <span class="p">}</span>

                <span class="n">HttpServerOperations</span> <span class="n">ops</span> <span class="o">=</span> <span class="p">(</span><span class="n">HttpServerOperations</span><span class="p">)</span><span class="n">connection</span><span class="p">;</span>
                <span class="n">Mono</span><span class="p">.</span><span class="na">fromDirect</span><span class="p">((</span><span class="n">Publisher</span><span class="p">)</span><span class="k">this</span><span class="p">.</span><span class="na">handler</span><span class="p">.</span><span class="na">apply</span><span class="p">(</span><span class="n">ops</span><span class="p">,</span> <span class="n">ops</span><span class="p">)).</span><span class="na">subscribe</span><span class="p">(</span><span class="n">ops</span><span class="p">.</span><span class="na">disposeSubscriber</span><span class="p">());</span>
            <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="n">Throwable</span> <span class="n">var4</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">log</span><span class="p">.</span><span class="na">error</span><span class="p">(</span><span class="n">ReactorNetty</span><span class="p">.</span><span class="na">format</span><span class="p">(</span><span class="n">connection</span><span class="p">.</span><span class="na">channel</span><span class="p">(),</span> <span class="s">""</span><span class="p">),</span> <span class="n">var4</span><span class="p">);</span>
                <span class="n">connection</span><span class="p">.</span><span class="na">channel</span><span class="p">().</span><span class="na">close</span><span class="p">();</span>
            <span class="p">}</span>
        <span class="p">}</span>

    <span class="p">}</span>
</code></pre>
     </div>
     <p>
      继续走到 TcpServerBind
     </p>
     <div class="codehilite">
      <pre><span></span><code>        <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onStateChange</span><span class="p">(</span><span class="n">Connection</span> <span class="n">connection</span><span class="p">,</span> <span class="n">State</span> <span class="n">newState</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">newState</span> <span class="o">==</span> <span class="n">State</span><span class="p">.</span><span class="na">DISCONNECTING</span> <span class="o">&amp;&amp;</span> <span class="n">connection</span><span class="p">.</span><span class="na">channel</span><span class="p">().</span><span class="na">isActive</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">connection</span><span class="p">.</span><span class="na">isPersistent</span><span class="p">())</span> <span class="p">{</span>
                <span class="n">connection</span><span class="p">.</span><span class="na">dispose</span><span class="p">();</span>
            <span class="p">}</span>

            <span class="k">this</span><span class="p">.</span><span class="na">childObs</span><span class="p">.</span><span class="na">onStateChange</span><span class="p">(</span><span class="n">connection</span><span class="p">,</span> <span class="n">newState</span><span class="p">);</span>
        <span class="p">}</span>
</code></pre>
     </div>
     <p>
      走到了很关键的一个： HttpServerOperations ，下面这个函数的 ctx 和 msg 也太熟悉不过了，明显的 netty 的 handler处理，请求入口
     </p>
     <div class="codehilite">
      <pre><span></span><code>    <span class="kd">protected</span> <span class="kt">void</span> <span class="nf">onInboundNext</span><span class="p">(</span><span class="n">ChannelHandlerContext</span> <span class="n">ctx</span><span class="p">,</span> <span class="n">Object</span> <span class="n">msg</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">msg</span> <span class="k">instanceof</span> <span class="n">HttpRequest</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">try</span> <span class="p">{</span>
                <span class="c1">// 调用</span>
                <span class="k">this</span><span class="p">.</span><span class="na">listener</span><span class="p">().</span><span class="na">onStateChange</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="n">HttpServerState</span><span class="p">.</span><span class="na">REQUEST_RECEIVED</span><span class="p">);</span>
            <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span> <span class="n">var4</span><span class="p">)</span> <span class="p">{</span>
                <span class="k">this</span><span class="p">.</span><span class="na">onInboundError</span><span class="p">(</span><span class="n">var4</span><span class="p">);</span>
                <span class="n">ReferenceCountUtil</span><span class="p">.</span><span class="na">release</span><span class="p">(</span><span class="n">msg</span><span class="p">);</span>
                <span class="k">return</span><span class="p">;</span>
            <span class="p">}</span>

            <span class="k">if</span> <span class="p">(</span><span class="n">msg</span> <span class="k">instanceof</span> <span class="n">FullHttpRequest</span><span class="p">)</span> <span class="p">{</span>
                <span class="kd">super</span><span class="p">.</span><span class="na">onInboundNext</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="n">msg</span><span class="p">);</span>
                <span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="na">isHttp2</span><span class="p">())</span> <span class="p">{</span>
                    <span class="k">this</span><span class="p">.</span><span class="na">onInboundComplete</span><span class="p">();</span>
                <span class="p">}</span>
            <span class="p">}</span>

        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">msg</span> <span class="k">instanceof</span> <span class="n">HttpContent</span><span class="p">)</span> <span class="p">{</span>
                <span class="k">if</span> <span class="p">(</span><span class="n">msg</span> <span class="o">!=</span> <span class="n">LastHttpContent</span><span class="p">.</span><span class="na">EMPTY_LAST_CONTENT</span><span class="p">)</span> <span class="p">{</span>
                    <span class="kd">super</span><span class="p">.</span><span class="na">onInboundNext</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="n">msg</span><span class="p">);</span>
                <span class="p">}</span>

                <span class="k">if</span> <span class="p">(</span><span class="n">msg</span> <span class="k">instanceof</span> <span class="n">LastHttpContent</span><span class="p">)</span> <span class="p">{</span>
                    <span class="k">this</span><span class="p">.</span><span class="na">onInboundComplete</span><span class="p">();</span>
                <span class="p">}</span>
            <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                <span class="kd">super</span><span class="p">.</span><span class="na">onInboundNext</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="n">msg</span><span class="p">);</span>
            <span class="p">}</span>

        <span class="p">}</span>
    <span class="p">}</span>
</code></pre>
     </div>
     <p>
      这个时候走到头了，我们跳出来看一看，梳理一下目前所得，发现我们搞清楚了一个请求接受，然后到 divide 的处理过程，梳理下大致如下：
     </p>
     <ul>
      <li>
       HttpServerOperations : 明显的netty的请求接收的地方，请求入口
      </li>
      <li>
       TcpServerBind
      </li>
      <li>
       HttpServerHandle
      </li>
      <li>
       ReactorHttpHandlerAdapter ：生成response和request
      </li>
      <li>
       ReactiveWebServerApplicationContext
      </li>
      <li>
       HttpWebHandlerAdapter ：exchange 的生成
      </li>
      <li>
       ExceptionHandlingWebHandler
      </li>
      <li>
       WebHandlerDecorator
      </li>
      <li>
       FilteringWebHandler
      </li>
      <li>
       DefaultWebFilterChain
      </li>
      <li>
       SoulWebHandler ：plugins调用链
      </li>
      <li>
       DividePlugin ：plugin具体处理
      </li>
     </ul>
     <h3 id="debug_1">
      逐步debug相关细节
     </h3>
     <p>
      这个时候参考网关模型，发现路由匹配之类的没有看到，没办法，细节部分没有清楚的就是: SoulWebHandler ,它的plugin调用的部分没有细看，于是我们进行如下的函数的debug，进入各个函数的调用（进入subscribe之类的时候就跳出来，点击进入下一个断点，IDEA debug左上角的箭头）
     </p>
     <div class="codehilite">
      <pre><span></span><code>        <span class="kd">public</span> <span class="n">Mono</span><span class="o">&lt;</span><span class="n">Void</span><span class="o">&gt;</span> <span class="nf">execute</span><span class="p">(</span><span class="kd">final</span> <span class="n">ServerWebExchange</span> <span class="n">exchange</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span> <span class="n">Mono</span><span class="p">.</span><span class="na">defer</span><span class="p">(()</span> <span class="o">-&gt;</span> <span class="p">{</span>
                <span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="na">index</span> <span class="o">&lt;</span> <span class="n">plugins</span><span class="p">.</span><span class="na">size</span><span class="p">())</span> <span class="p">{</span>
                    <span class="n">SoulPlugin</span> <span class="n">plugin</span> <span class="o">=</span> <span class="n">plugins</span><span class="p">.</span><span class="na">get</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="na">index</span><span class="o">++</span><span class="p">);</span>
                    <span class="n">Boolean</span> <span class="n">skip</span> <span class="o">=</span> <span class="n">plugin</span><span class="p">.</span><span class="na">skip</span><span class="p">(</span><span class="n">exchange</span><span class="p">);</span>
                    <span class="k">if</span> <span class="p">(</span><span class="n">skip</span><span class="p">)</span> <span class="p">{</span>
                        <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="na">execute</span><span class="p">(</span><span class="n">exchange</span><span class="p">);</span>
                    <span class="p">}</span>
                    <span class="k">return</span> <span class="n">plugin</span><span class="p">.</span><span class="na">execute</span><span class="p">(</span><span class="n">exchange</span><span class="p">,</span> <span class="k">this</span><span class="p">);</span>
                <span class="p">}</span>
                <span class="k">return</span> <span class="n">Mono</span><span class="p">.</span><span class="na">empty</span><span class="p">();</span>
            <span class="p">});</span>
        <span class="p">}</span>
</code></pre>
     </div>
     <p>
      我们逐步调试上面的那个函数，查看变量： plugins，内容大致如下，后面false和true是变量 skip。发现是true就不执行，看函数也能大致猜的到,各个插件的skip情况如下：
     </p>
     <ul>
      <li>
       GlobalPlugin : false
      </li>
      <li>
       SignPlugin : false
      </li>
      <li>
       WafPlugin: false
      </li>
      <li>
       RateLimiterPlugin : false
      </li>
      <li>
       HystrixPlugin : false
      </li>
      <li>
       Resilience4JPlugin : false
      </li>
      <li>
       DividePlugin : false
      </li>
      <li>
       WebClientPlugin : false
      </li>
      <li>
       WebsocketPlugin : true
      </li>
      <li>
       BodyParamPlugin : false
      </li>
      <li>
       AlibabaDubblePlugin : true
      </li>
      <li>
       MonitorPlugin : false
      </li>
      <li>
       WebClientResponsePlugin : false
      </li>
      <li>
       DubboResponsePlugin : true
      </li>
     </ul>
     <p>
      调试的时候跟着进去，进去以后一步一步的走即可
     </p>
     <p>
      我们调试进入前几个plugin都是没有执行到下面代码中的if，在 divide plugin 执行了，我们跟着进入看看，看到了疑似路由匹配的 rules，还有 match，猜测这是路由匹配相关
     </p>
     <div class="codehilite">
      <pre><span></span><code>    <span class="kd">public</span> <span class="n">Mono</span><span class="o">&lt;</span><span class="n">Void</span><span class="o">&gt;</span> <span class="nf">execute</span><span class="p">(</span><span class="kd">final</span> <span class="n">ServerWebExchange</span> <span class="n">exchange</span><span class="p">,</span> <span class="kd">final</span> <span class="n">SoulPluginChain</span> <span class="n">chain</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">String</span> <span class="n">pluginName</span> <span class="o">=</span> <span class="n">named</span><span class="p">();</span>
        <span class="kd">final</span> <span class="n">PluginData</span> <span class="n">pluginData</span> <span class="o">=</span> <span class="n">BaseDataCache</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">obtainPluginData</span><span class="p">(</span><span class="n">pluginName</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">pluginData</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&amp;&amp;</span> <span class="n">pluginData</span><span class="p">.</span><span class="na">getEnabled</span><span class="p">())</span> <span class="p">{</span>
            <span class="kd">final</span> <span class="n">Collection</span><span class="o">&lt;</span><span class="n">SelectorData</span><span class="o">&gt;</span> <span class="n">selectors</span> <span class="o">=</span> <span class="n">BaseDataCache</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">obtainSelectorData</span><span class="p">(</span><span class="n">pluginName</span><span class="p">);</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">CollectionUtils</span><span class="p">.</span><span class="na">isEmpty</span><span class="p">(</span><span class="n">selectors</span><span class="p">))</span> <span class="p">{</span>
                <span class="k">return</span> <span class="n">handleSelectorIsNull</span><span class="p">(</span><span class="n">pluginName</span><span class="p">,</span> <span class="n">exchange</span><span class="p">,</span> <span class="n">chain</span><span class="p">);</span>
            <span class="p">}</span>
            <span class="kd">final</span> <span class="n">SelectorData</span> <span class="n">selectorData</span> <span class="o">=</span> <span class="n">matchSelector</span><span class="p">(</span><span class="n">exchange</span><span class="p">,</span> <span class="n">selectors</span><span class="p">);</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">Objects</span><span class="p">.</span><span class="na">isNull</span><span class="p">(</span><span class="n">selectorData</span><span class="p">))</span> <span class="p">{</span>
                <span class="k">return</span> <span class="n">handleSelectorIsNull</span><span class="p">(</span><span class="n">pluginName</span><span class="p">,</span> <span class="n">exchange</span><span class="p">,</span> <span class="n">chain</span><span class="p">);</span>
            <span class="p">}</span>
            <span class="n">selectorLog</span><span class="p">(</span><span class="n">selectorData</span><span class="p">,</span> <span class="n">pluginName</span><span class="p">);</span>
            <span class="kd">final</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">RuleData</span><span class="o">&gt;</span> <span class="n">rules</span> <span class="o">=</span> <span class="n">BaseDataCache</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">obtainRuleData</span><span class="p">(</span><span class="n">selectorData</span><span class="p">.</span><span class="na">getId</span><span class="p">());</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">CollectionUtils</span><span class="p">.</span><span class="na">isEmpty</span><span class="p">(</span><span class="n">rules</span><span class="p">))</span> <span class="p">{</span>
                <span class="k">return</span> <span class="n">handleRuleIsNull</span><span class="p">(</span><span class="n">pluginName</span><span class="p">,</span> <span class="n">exchange</span><span class="p">,</span> <span class="n">chain</span><span class="p">);</span>
            <span class="p">}</span>
            <span class="n">RuleData</span> <span class="n">rule</span><span class="p">;</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">selectorData</span><span class="p">.</span><span class="na">getType</span><span class="p">()</span> <span class="o">==</span> <span class="n">SelectorTypeEnum</span><span class="p">.</span><span class="na">FULL_FLOW</span><span class="p">.</span><span class="na">getCode</span><span class="p">())</span> <span class="p">{</span>
                <span class="c1">//get last</span>
                <span class="n">rule</span> <span class="o">=</span> <span class="n">rules</span><span class="p">.</span><span class="na">get</span><span class="p">(</span><span class="n">rules</span><span class="p">.</span><span class="na">size</span><span class="p">()</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
            <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                <span class="c1">// divide plugin 执行到这步，在rules，发现我们配置的规则，猜测这里是路由匹配</span>
                <span class="n">rule</span> <span class="o">=</span> <span class="n">matchRule</span><span class="p">(</span><span class="n">exchange</span><span class="p">,</span> <span class="n">rules</span><span class="p">);</span>
            <span class="p">}</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">Objects</span><span class="p">.</span><span class="na">isNull</span><span class="p">(</span><span class="n">rule</span><span class="p">))</span> <span class="p">{</span>
                <span class="k">return</span> <span class="n">handleRuleIsNull</span><span class="p">(</span><span class="n">pluginName</span><span class="p">,</span> <span class="n">exchange</span><span class="p">,</span> <span class="n">chain</span><span class="p">);</span>
            <span class="p">}</span>
            <span class="n">ruleLog</span><span class="p">(</span><span class="n">rule</span><span class="p">,</span> <span class="n">pluginName</span><span class="p">);</span>
            <span class="k">return</span> <span class="n">doExecute</span><span class="p">(</span><span class="n">exchange</span><span class="p">,</span> <span class="n">chain</span><span class="p">,</span> <span class="n">selectorData</span><span class="p">,</span> <span class="n">rule</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="n">chain</span><span class="p">.</span><span class="na">execute</span><span class="p">(</span><span class="n">exchange</span><span class="p">);</span>
    <span class="p">}</span>
</code></pre>
     </div>
     <p>
      继续debug，进入： WebClientPlugin ，看到了疑似发送请求给后台服务器，相关代码如下：
     </p>
     <div class="codehilite">
      <pre><span></span><code>    <span class="kd">public</span> <span class="n">Mono</span><span class="o">&lt;</span><span class="n">Void</span><span class="o">&gt;</span> <span class="nf">execute</span><span class="p">(</span><span class="kd">final</span> <span class="n">ServerWebExchange</span> <span class="n">exchange</span><span class="p">,</span> <span class="kd">final</span> <span class="n">SoulPluginChain</span> <span class="n">chain</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">final</span> <span class="n">SoulContext</span> <span class="n">soulContext</span> <span class="o">=</span> <span class="n">exchange</span><span class="p">.</span><span class="na">getAttribute</span><span class="p">(</span><span class="n">Constants</span><span class="p">.</span><span class="na">CONTEXT</span><span class="p">);</span>
        <span class="k">assert</span> <span class="n">soulContext</span> <span class="o">!=</span> <span class="kc">null</span><span class="p">;</span>
        <span class="n">String</span> <span class="n">urlPath</span> <span class="o">=</span> <span class="n">exchange</span><span class="p">.</span><span class="na">getAttribute</span><span class="p">(</span><span class="n">Constants</span><span class="p">.</span><span class="na">HTTP_URL</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">StringUtils</span><span class="p">.</span><span class="na">isEmpty</span><span class="p">(</span><span class="n">urlPath</span><span class="p">))</span> <span class="p">{</span>
            <span class="n">Object</span> <span class="n">error</span> <span class="o">=</span> <span class="n">SoulResultWrap</span><span class="p">.</span><span class="na">error</span><span class="p">(</span><span class="n">SoulResultEnum</span><span class="p">.</span><span class="na">CANNOT_FIND_URL</span><span class="p">.</span><span class="na">getCode</span><span class="p">(),</span> <span class="n">SoulResultEnum</span><span class="p">.</span><span class="na">CANNOT_FIND_URL</span><span class="p">.</span><span class="na">getMsg</span><span class="p">(),</span> <span class="kc">null</span><span class="p">);</span>
            <span class="k">return</span> <span class="n">WebFluxResultUtils</span><span class="p">.</span><span class="na">result</span><span class="p">(</span><span class="n">exchange</span><span class="p">,</span> <span class="n">error</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="kt">long</span> <span class="n">timeout</span> <span class="o">=</span> <span class="p">(</span><span class="kt">long</span><span class="p">)</span> <span class="n">Optional</span><span class="p">.</span><span class="na">ofNullable</span><span class="p">(</span><span class="n">exchange</span><span class="p">.</span><span class="na">getAttribute</span><span class="p">(</span><span class="n">Constants</span><span class="p">.</span><span class="na">HTTP_TIME_OUT</span><span class="p">)).</span><span class="na">orElse</span><span class="p">(</span><span class="mi">3000L</span><span class="p">);</span>
        <span class="kt">int</span> <span class="n">retryTimes</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="n">Optional</span><span class="p">.</span><span class="na">ofNullable</span><span class="p">(</span><span class="n">exchange</span><span class="p">.</span><span class="na">getAttribute</span><span class="p">(</span><span class="n">Constants</span><span class="p">.</span><span class="na">HTTP_RETRY</span><span class="p">)).</span><span class="na">orElse</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
        <span class="n">log</span><span class="p">.</span><span class="na">info</span><span class="p">(</span><span class="s">"The request urlPath is {}, retryTimes is {}"</span><span class="p">,</span> <span class="n">urlPath</span><span class="p">,</span> <span class="n">retryTimes</span><span class="p">);</span>
        <span class="n">HttpMethod</span> <span class="n">method</span> <span class="o">=</span> <span class="n">HttpMethod</span><span class="p">.</span><span class="na">valueOf</span><span class="p">(</span><span class="n">exchange</span><span class="p">.</span><span class="na">getRequest</span><span class="p">().</span><span class="na">getMethodValue</span><span class="p">());</span>
        <span class="n">WebClient</span><span class="p">.</span><span class="na">RequestBodySpec</span> <span class="n">requestBodySpec</span> <span class="o">=</span> <span class="n">webClient</span><span class="p">.</span><span class="na">method</span><span class="p">(</span><span class="n">method</span><span class="p">).</span><span class="na">uri</span><span class="p">(</span><span class="n">urlPath</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">handleRequestBody</span><span class="p">(</span><span class="n">requestBodySpec</span><span class="p">,</span> <span class="n">exchange</span><span class="p">,</span> <span class="n">timeout</span><span class="p">,</span> <span class="n">retryTimes</span><span class="p">,</span> <span class="n">chain</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="kd">private</span> <span class="n">Mono</span><span class="o">&lt;</span><span class="n">Void</span><span class="o">&gt;</span> <span class="nf">handleRequestBody</span><span class="p">(</span><span class="kd">final</span> <span class="n">WebClient</span><span class="p">.</span><span class="na">RequestBodySpec</span> <span class="n">requestBodySpec</span><span class="p">,</span>
                                         <span class="kd">final</span> <span class="n">ServerWebExchange</span> <span class="n">exchange</span><span class="p">,</span>
                                         <span class="kd">final</span> <span class="kt">long</span> <span class="n">timeout</span><span class="p">,</span>
                                         <span class="kd">final</span> <span class="kt">int</span> <span class="n">retryTimes</span><span class="p">,</span>
                                         <span class="kd">final</span> <span class="n">SoulPluginChain</span> <span class="n">chain</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// 下面这段代码太想前端的 ajax 调用了，猜测这是 请求发送</span>
        <span class="k">return</span> <span class="n">requestBodySpec</span><span class="p">.</span><span class="na">headers</span><span class="p">(</span><span class="n">httpHeaders</span> <span class="o">-&gt;</span> <span class="p">{</span>
            <span class="n">httpHeaders</span><span class="p">.</span><span class="na">addAll</span><span class="p">(</span><span class="n">exchange</span><span class="p">.</span><span class="na">getRequest</span><span class="p">().</span><span class="na">getHeaders</span><span class="p">());</span>
            <span class="n">httpHeaders</span><span class="p">.</span><span class="na">remove</span><span class="p">(</span><span class="n">HttpHeaders</span><span class="p">.</span><span class="na">HOST</span><span class="p">);</span>
        <span class="p">})</span>
                <span class="p">.</span><span class="na">contentType</span><span class="p">(</span><span class="n">buildMediaType</span><span class="p">(</span><span class="n">exchange</span><span class="p">))</span>
                <span class="p">.</span><span class="na">body</span><span class="p">(</span><span class="n">BodyInserters</span><span class="p">.</span><span class="na">fromDataBuffers</span><span class="p">(</span><span class="n">exchange</span><span class="p">.</span><span class="na">getRequest</span><span class="p">().</span><span class="na">getBody</span><span class="p">()))</span>
                <span class="p">.</span><span class="na">exchange</span><span class="p">()</span>
                <span class="p">.</span><span class="na">doOnError</span><span class="p">(</span><span class="n">e</span> <span class="o">-&gt;</span> <span class="n">log</span><span class="p">.</span><span class="na">error</span><span class="p">(</span><span class="n">e</span><span class="p">.</span><span class="na">getMessage</span><span class="p">()))</span>
                <span class="p">.</span><span class="na">timeout</span><span class="p">(</span><span class="n">Duration</span><span class="p">.</span><span class="na">ofMillis</span><span class="p">(</span><span class="n">timeout</span><span class="p">))</span>
                <span class="p">.</span><span class="na">retryWhen</span><span class="p">(</span><span class="n">Retry</span><span class="p">.</span><span class="na">onlyIf</span><span class="p">(</span><span class="n">x</span> <span class="o">-&gt;</span> <span class="n">x</span><span class="p">.</span><span class="na">exception</span><span class="p">()</span> <span class="k">instanceof</span> <span class="n">ConnectTimeoutException</span><span class="p">)</span>
                    <span class="p">.</span><span class="na">retryMax</span><span class="p">(</span><span class="n">retryTimes</span><span class="p">)</span>
                    <span class="p">.</span><span class="na">backoff</span><span class="p">(</span><span class="n">Backoff</span><span class="p">.</span><span class="na">exponential</span><span class="p">(</span><span class="n">Duration</span><span class="p">.</span><span class="na">ofMillis</span><span class="p">(</span><span class="mi">200</span><span class="p">),</span> <span class="n">Duration</span><span class="p">.</span><span class="na">ofSeconds</span><span class="p">(</span><span class="mi">20</span><span class="p">),</span> <span class="mi">2</span><span class="p">,</span> <span class="kc">true</span><span class="p">)))</span>
                <span class="p">.</span><span class="na">flatMap</span><span class="p">(</span><span class="n">e</span> <span class="o">-&gt;</span> <span class="n">doNext</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="n">exchange</span><span class="p">,</span> <span class="n">chain</span><span class="p">));</span>

    <span class="p">}</span>

    <span class="kd">private</span> <span class="n">Mono</span><span class="o">&lt;</span><span class="n">Void</span><span class="o">&gt;</span> <span class="nf">doNext</span><span class="p">(</span><span class="kd">final</span> <span class="n">ClientResponse</span> <span class="n">res</span><span class="p">,</span> <span class="kd">final</span> <span class="n">ServerWebExchange</span> <span class="n">exchange</span><span class="p">,</span> <span class="kd">final</span> <span class="n">SoulPluginChain</span> <span class="n">chain</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">res</span><span class="p">.</span><span class="na">statusCode</span><span class="p">().</span><span class="na">is2xxSuccessful</span><span class="p">())</span> <span class="p">{</span>
            <span class="n">exchange</span><span class="p">.</span><span class="na">getAttributes</span><span class="p">().</span><span class="na">put</span><span class="p">(</span><span class="n">Constants</span><span class="p">.</span><span class="na">CLIENT_RESPONSE_RESULT_TYPE</span><span class="p">,</span> <span class="n">ResultEnum</span><span class="p">.</span><span class="na">SUCCESS</span><span class="p">.</span><span class="na">getName</span><span class="p">());</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="n">exchange</span><span class="p">.</span><span class="na">getAttributes</span><span class="p">().</span><span class="na">put</span><span class="p">(</span><span class="n">Constants</span><span class="p">.</span><span class="na">CLIENT_RESPONSE_RESULT_TYPE</span><span class="p">,</span> <span class="n">ResultEnum</span><span class="p">.</span><span class="na">ERROR</span><span class="p">.</span><span class="na">getName</span><span class="p">());</span>
        <span class="p">}</span>
        <span class="n">exchange</span><span class="p">.</span><span class="na">getAttributes</span><span class="p">().</span><span class="na">put</span><span class="p">(</span><span class="n">Constants</span><span class="p">.</span><span class="na">CLIENT_RESPONSE_ATTR</span><span class="p">,</span> <span class="n">res</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">chain</span><span class="p">.</span><span class="na">execute</span><span class="p">(</span><span class="n">exchange</span><span class="p">);</span>
    <span class="p">}</span>
</code></pre>
     </div>
     <p>
      继续进入，来到： WebClientResponsePlugin ，发现疑似 response 返回给客户端的代码
     </p>
     <div class="codehilite">
      <pre><span></span><code>    <span class="kd">public</span> <span class="n">Mono</span><span class="o">&lt;</span><span class="n">Void</span><span class="o">&gt;</span> <span class="nf">execute</span><span class="p">(</span><span class="kd">final</span> <span class="n">ServerWebExchange</span> <span class="n">exchange</span><span class="p">,</span> <span class="kd">final</span> <span class="n">SoulPluginChain</span> <span class="n">chain</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">chain</span><span class="p">.</span><span class="na">execute</span><span class="p">(</span><span class="n">exchange</span><span class="p">).</span><span class="na">then</span><span class="p">(</span><span class="n">Mono</span><span class="p">.</span><span class="na">defer</span><span class="p">(()</span> <span class="o">-&gt;</span> <span class="p">{</span>
            <span class="n">ServerHttpResponse</span> <span class="n">response</span> <span class="o">=</span> <span class="n">exchange</span><span class="p">.</span><span class="na">getResponse</span><span class="p">();</span>
            <span class="n">ClientResponse</span> <span class="n">clientResponse</span> <span class="o">=</span> <span class="n">exchange</span><span class="p">.</span><span class="na">getAttribute</span><span class="p">(</span><span class="n">Constants</span><span class="p">.</span><span class="na">CLIENT_RESPONSE_ATTR</span><span class="p">);</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">Objects</span><span class="p">.</span><span class="na">isNull</span><span class="p">(</span><span class="n">clientResponse</span><span class="p">)</span>
                    <span class="o">||</span> <span class="n">response</span><span class="p">.</span><span class="na">getStatusCode</span><span class="p">()</span> <span class="o">==</span> <span class="n">HttpStatus</span><span class="p">.</span><span class="na">BAD_GATEWAY</span>
                    <span class="o">||</span> <span class="n">response</span><span class="p">.</span><span class="na">getStatusCode</span><span class="p">()</span> <span class="o">==</span> <span class="n">HttpStatus</span><span class="p">.</span><span class="na">INTERNAL_SERVER_ERROR</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">Object</span> <span class="n">error</span> <span class="o">=</span> <span class="n">SoulResultWrap</span><span class="p">.</span><span class="na">error</span><span class="p">(</span><span class="n">SoulResultEnum</span><span class="p">.</span><span class="na">SERVICE_RESULT_ERROR</span><span class="p">.</span><span class="na">getCode</span><span class="p">(),</span> <span class="n">SoulResultEnum</span><span class="p">.</span><span class="na">SERVICE_RESULT_ERROR</span><span class="p">.</span><span class="na">getMsg</span><span class="p">(),</span> <span class="kc">null</span><span class="p">);</span>
                <span class="k">return</span> <span class="n">WebFluxResultUtils</span><span class="p">.</span><span class="na">result</span><span class="p">(</span><span class="n">exchange</span><span class="p">,</span> <span class="n">error</span><span class="p">);</span>
            <span class="p">}</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">response</span><span class="p">.</span><span class="na">getStatusCode</span><span class="p">()</span> <span class="o">==</span> <span class="n">HttpStatus</span><span class="p">.</span><span class="na">GATEWAY_TIMEOUT</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">Object</span> <span class="n">error</span> <span class="o">=</span> <span class="n">SoulResultWrap</span><span class="p">.</span><span class="na">error</span><span class="p">(</span><span class="n">SoulResultEnum</span><span class="p">.</span><span class="na">SERVICE_TIMEOUT</span><span class="p">.</span><span class="na">getCode</span><span class="p">(),</span> <span class="n">SoulResultEnum</span><span class="p">.</span><span class="na">SERVICE_TIMEOUT</span><span class="p">.</span><span class="na">getMsg</span><span class="p">(),</span> <span class="kc">null</span><span class="p">);</span>
                <span class="k">return</span> <span class="n">WebFluxResultUtils</span><span class="p">.</span><span class="na">result</span><span class="p">(</span><span class="n">exchange</span><span class="p">,</span> <span class="n">error</span><span class="p">);</span>
            <span class="p">}</span>
            <span class="n">response</span><span class="p">.</span><span class="na">setStatusCode</span><span class="p">(</span><span class="n">clientResponse</span><span class="p">.</span><span class="na">statusCode</span><span class="p">());</span>
            <span class="n">response</span><span class="p">.</span><span class="na">getCookies</span><span class="p">().</span><span class="na">putAll</span><span class="p">(</span><span class="n">clientResponse</span><span class="p">.</span><span class="na">cookies</span><span class="p">());</span>
            <span class="n">response</span><span class="p">.</span><span class="na">getHeaders</span><span class="p">().</span><span class="na">putAll</span><span class="p">(</span><span class="n">clientResponse</span><span class="p">.</span><span class="na">headers</span><span class="p">().</span><span class="na">asHttpHeaders</span><span class="p">());</span>
            <span class="c1">// 疑似响应返回</span>
            <span class="k">return</span> <span class="n">response</span><span class="p">.</span><span class="na">writeWith</span><span class="p">(</span><span class="n">clientResponse</span><span class="p">.</span><span class="na">body</span><span class="p">(</span><span class="n">BodyExtractors</span><span class="p">.</span><span class="na">toDataBuffers</span><span class="p">()));</span>
        <span class="p">}));</span>
    <span class="p">}</span>
</code></pre>
     </div>
     <p>
      经过一通调试，感觉 DividePlugin 、WebClientPlugin 、 WebClientResponsePlugin 非常的可疑，我们取消所有的断点，然后对他们三个打上断点进行调试
     </p>
     <p>
      首先对 DividePlugin 进行测试，我们发送一个没有配置的请求 http://localhost:9195/get ,发送后一路debug下来，发现返回结果如下：
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="p">{</span>
    <span class="nt">"code"</span><span class="p">:</span> <span class="mi">-107</span><span class="p">,</span>
    <span class="nt">"message"</span><span class="p">:</span> <span class="s2">"Can not find selector, please check your configuration!"</span><span class="p">,</span>
    <span class="nt">"data"</span><span class="p">:</span> <span class="kc">null</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      符合我们的预期，我们看下相关的代码，后面还测试了配置不正确的，发现都会进入下面的调用函数：
     </p>
     <div class="codehilite">
      <pre><span></span><code>    <span class="kd">public</span> <span class="kd">static</span> <span class="n">Mono</span><span class="o">&lt;</span><span class="n">Void</span><span class="o">&gt;</span> <span class="nf">result</span><span class="p">(</span><span class="kd">final</span> <span class="n">ServerWebExchange</span> <span class="n">exchange</span><span class="p">,</span> <span class="kd">final</span> <span class="n">Object</span> <span class="n">result</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">exchange</span><span class="p">.</span><span class="na">getResponse</span><span class="p">().</span><span class="na">getHeaders</span><span class="p">().</span><span class="na">setContentType</span><span class="p">(</span><span class="n">MediaType</span><span class="p">.</span><span class="na">APPLICATION_JSON</span><span class="p">);</span>
        <span class="c1">// 这个exchange.getResponse().writeWith 很前面看到基本一样，可以猜测soul里面估计都是这样返回响应的</span>
        <span class="k">return</span> <span class="n">exchange</span><span class="p">.</span><span class="na">getResponse</span><span class="p">().</span><span class="na">writeWith</span><span class="p">(</span><span class="n">Mono</span><span class="p">.</span><span class="na">just</span><span class="p">(</span><span class="n">exchange</span><span class="p">.</span><span class="na">getResponse</span><span class="p">()</span>
                <span class="p">.</span><span class="na">bufferFactory</span><span class="p">().</span><span class="na">wrap</span><span class="p">(</span><span class="n">Objects</span><span class="p">.</span><span class="na">requireNonNull</span><span class="p">(</span><span class="n">JsonUtils</span><span class="p">.</span><span class="na">toJson</span><span class="p">(</span><span class="n">result</span><span class="p">)).</span><span class="na">getBytes</span><span class="p">())));</span>
    <span class="p">}</span>
</code></pre>
     </div>
     <p>
      继续测试正确的请求，WebClientPlugin 经过上面的分析和根据函数大致代码判断，handleRequestBody 发送请求，doNext 可以收到请求结果，我们在 doNext上打上断点，发现果然在后台服务端收到了请求（自己写的netty服务，并打印日志），验证我们这里是请求发送的猜想
     </p>
     <p>
      WebClientResponsePlugin 我们在 execute 函数打上断点，调试的时候注意到，进入了两次，一次是 chain.execute(exchange)，一次是后面的then，这个有点像lamda表达式（也可以类比为vue的请求），而且then是等所有 plugin 都运行以后才执行，执行完以后进客户端就得到了结果
     </p>
     <p>
      具体的发送逻辑还没有看懂，但不影响这次的处理流程解析。再debug的时候还有一个不断循环调用的地方，我们回过头来去看一下它，看看有什么分析疏漏没
     </p>
     <p>
      在类： DefaultWebFilterChain 中有这么一点循环调用，代码如下：
     </p>
     <div class="codehilite">
      <pre><span></span><code>    <span class="kd">public</span> <span class="n">Mono</span><span class="o">&lt;</span><span class="n">Void</span><span class="o">&gt;</span> <span class="nf">filter</span><span class="p">(</span><span class="n">ServerWebExchange</span> <span class="n">exchange</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">Mono</span><span class="p">.</span><span class="na">defer</span><span class="p">(()</span> <span class="o">-&gt;</span> <span class="p">{</span>
            <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="na">currentFilter</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&amp;&amp;</span> <span class="k">this</span><span class="p">.</span><span class="na">chain</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">?</span> <span class="k">this</span><span class="p">.</span><span class="na">invokeFilter</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="na">currentFilter</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="na">chain</span><span class="p">,</span> <span class="n">exchange</span><span class="p">)</span> <span class="p">:</span> <span class="k">this</span><span class="p">.</span><span class="na">handler</span><span class="p">.</span><span class="na">handle</span><span class="p">(</span><span class="n">exchange</span><span class="p">);</span>
        <span class="p">});</span>
    <span class="p">}</span>
</code></pre>
     </div>
     <p>
      我们查看其相关类有下面几个，进入相应的类看了看，大致如下：
     </p>
     <ul>
      <li>
       MetricsWebFilter : 没看懂
      </li>
      <li>
       HealthFilter : 感觉类似监控检查，可以直接方法，因为是本地的；"/actuator/health", "/health_check"，尝试了下确实不走后面的处理逻辑，直接返回了
      </li>
      <li>
       FileSizeFilter ：文件上传大小限制？MediaType.MULTIPART_FORM_DATA.isCompatibleWith(mediaType)
      </li>
      <li>
       WebSocketParamFilter ：不太清楚其功能
      </li>
      <li>
       HiddenHttpMethodFilter ：看到好像没有啥逻辑代码
      </li>
     </ul>
     <p>
      得到了健康检查之类的直接在 HealthFilter 中返回，文件上传大小限制功能也在 filter 中，其他的不太清楚，但不影响大局
     </p>
     <h2 id="_5">
      总结
     </h2>
     <p>
      经过总结梳理，得到下面的初步处理流程概览：
     </p>
     <p>
      <img alt="" src="https://github.com/lw1243925457/SE-Notes/raw/master/profession/program/%E5%BC%80%E6%BA%90/soul/picture/Soulprocessfirst.png"/>
     </p>
     <ul>
      <li>
       HttpServerOperations : 明显的netty的请求接收的地方，请求入口
      </li>
      <li>
       ReactorHttpHandlerAdapter ：生成response和request
      </li>
      <li>
       HttpWebHandlerAdapter ：exchange 的生成
      </li>
      <li>
       FilteringWebHandler : filter 操作
      </li>
      <li>
       SoulWebHandler ：plugins调用链
      </li>
     </ul>
     <p>
      请求由netty收到后，来到Filter，这里进行一些处理：健康检查，文件大小检查等待，然后来到核心的 plugins，这里有三个部分的plugin需要注意（自己给它分的，初步猜测）：
     </p>
     <ul>
      <li>
       前置处理：这里的 plugin 都会进行匹配，感觉就是针对配置后的url进行认证、黑名单、限流、降级、熔断等操作
      </li>
      <li>
       请求发送：这里对HTTP、websocket、rpc、文件上传（这个是猜测）这四种请求进行处理，发送到后端服务器
      </li>
      <li>
       响应返回：这里就两种响应，HTTP和rpc，拿到后返回给客户端
      </li>
     </ul>
     <p>
      可以看到plugins非常的核心，关键功能都是在这里实现的，其中 divide plugin 好像扮演了路由匹配的角色，在Soul中就没有明显单独的路由匹配
     </p>
     <p>
      请求和响应的处理也是在 plugins 进行处理的
     </p>
     <h2 id="soul">
      Soul网关源码解析文章列表
     </h2>
     <h3 id="_6">
      掘金
     </h3>
     <h4 id="_7">
      了解与初步运行
     </h4>
     <ul>
      <li>
       <a href="https://juejin.cn/post/6917864624423436296">
        Soul网关源码解析（一） 概览
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6917865804121767944">
        Soul网关源码解析（二）代码初步运行
       </a>
      </li>
     </ul>
     <h4 id="_8">
      请求处理流程解析
     </h4>
     <ul>
      <li>
       <a href="https://juejin.cn/post/6917866538712334343">
        Soul网关源码解析（三）请求处理概览
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6917867369909977102">
        Soul网关源码解析（四）Dubbo请求概览
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6918575905962983438">
        Soul网关源码解析（五）请求类型探索
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6918736260467015693">
        Soul网关源码解析（六）Sofa请求处理概览
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6919348164944232455/">
        Soul网关源码解析（七）限流插件初探
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6919774553241550855/">
        Soul网关源码解析（八）路由匹配初探
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6920074307590684685/">
        Soul网关源码解析（九）插件配置加载初探
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6920142348617777166">
        Soul网关源码解析（十）自定义简单插件编写
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6920596034171174925">
        Soul网关源码解析（十一）请求处理小结
       </a>
      </li>
     </ul>
     <h4 id="_9">
      数据同步解析
     </h4>
     <ul>
      <li>
       <a href="https://juejin.cn/post/6920596173925384206">
        Soul网关源码解析（十二）数据同步初探
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6920596028505178125">
        Soul网关源码解析（十三）Websocket同步数据-Bootstrap端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6920597298674302983">
        Soul网关源码解析（十四）HTTP数据同步-Bootstrap端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6920764643967238151">
        Soul网关源码解析（十五）Zookeeper数据同步-Bootstrap端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6921170233868845064">
        Soul网关源码解析（十六）Nacos数据同步示例运行
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6921325882753695757/">
        Soul网关源码解析（十七）Nacos数据同步解析-Bootstrap端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6921495273122463751/">
        Soul网关源码解析（十八）Zookeeper数据同步初探-Admin端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6921621915995996168/">
        Soul网关源码解析（十九）Nacos数据同步初始化修复-Admin端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6921988280187617287/">
        Soul网关源码解析（二十）Websocket数据同步-Admin端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6922301585288593416/">
        Soul网关源码解析（二十一）HTTP长轮询数据同步-Admin端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6922584596810825735/">
        Soul网关源码解析（二十二）数据同步小结
       </a>
      </li>
     </ul>
     <h4 id="soul-client">
      Soul-Client模块
     </h4>
     <ul>
      <li>
       <a href="https://juejin.cn/post/6922643958455599111">
        Soul网关源码解析（二十三）SoulSpringMvcClient注解
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6922722161702469640/">
        Soul网关源码解析（二十四）SoulDubboClient注解
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6922745260435046408/">
        Soul网关源码解析（二十五）Soul-Client模块小结
       </a>
      </li>
     </ul>
     <h4 id="_10">
      总览
     </h4>
     <ul>
      <li>
       <a href="https://juejin.cn/post/6922960265663217678/">
        Soul网关源码解析（二十六）初步总览
       </a>
      </li>
     </ul>
     <h4 id="_11">
      番外
     </h4>
     <ul>
      <li>
       <a href="https://juejin.cn/post/6918947689564471309">
        Soul网关源码阅读番外篇（一） HTTP参数请求错误
       </a>
      </li>
     </ul>
    </article>
   </div>
   <!-- Footer -->
   <footer id="footer">
    <p class="copyright">
     © Untitled. Design:
     <a href="https://html5up.net">
      HTML5 UP
     </a>
     .
    </p>
   </footer>
  </div>
  <!-- BG -->
  <div id="bg">
  </div>
  <!-- Scripts -->
  <script src="../assets/js/jquery.min.js">
  </script>
  <script src="../assets/js/browser.min.js">
  </script>
  <script src="../assets/js/breakpoints.min.js">
  </script>
  <script src="../assets/js/util.js">
  </script>
  <script src="../assets/js/main.js">
  </script>
 </body>
</html>
